package gupao.concurrency.threads.aqs;

import lombok.extern.slf4j.Slf4j;

import java.util.LinkedList;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;

@Slf4j
public class ProductsContainer<T> {
    class Sync extends AbstractQueuedSynchronizer {
        @Override
        protected boolean tryAcquire(int arg) {
            if(compareAndSetState(0,1)){
                return true;
            }
            return false;
        }
        @Override
        protected boolean tryRelease(int arg) {
            if(getState() == 0 || Thread.currentThread() != getExclusiveOwnerThread()){
                throw new IllegalMonitorStateException();
            }
            setState(0);
            return true;
        }
        protected final boolean isHeldExclusively() {
            return Thread.currentThread() == getExclusiveOwnerThread();
        }
        final ConditionObject newCondition() {
            return new ConditionObject();
        }
    }
    private Sync innerSync = new ProductsContainer.Sync();
    private Condition notFull = innerSync.newCondition(); // list.size() < max_size
    private Condition notEmpty = innerSync.newCondition(); //list.size() > 0
    public void put(T product) throws InterruptedException{
        innerSync.acquire(1);
        try{
            while ( products.size() == maxSize ){
                notFull.await();
            }
            products.add(product);
            notEmpty.signalAll();
        }finally {
            innerSync.release(1);
        }
    }
    public T get() throws InterruptedException{
        innerSync.acquire(1);
        try{
            while( products.size() == 0 ){
                notEmpty.await();
            }
            T product = products.poll();
            notFull.signalAll();
            return product;
        }finally {
            innerSync.release(1);
        }
    }
    private LinkedList<T> products;
    private int maxSize = 20;
    public ProductsContainer(int maxSize) {
        this.products = new LinkedList<>();
        this.maxSize = maxSize;
    }
    public int getSize(){
        return products.size();
    }
}
